// // Copyright (c) 2009 All Right Reserved // // Stephen Toub // stoub@microsoft.com // 2009-01-01 // Contains ... namespace LargoCommon.Midi { using System; using System.IO; using System.Text; using JetBrains.Annotations; using Music; /// Represents a voice category message. [Serializable] public abstract class VoiceEvent : MidiEvent { #region Fields /// The status identifier (0x0 through 0xF) for this voice event. private readonly byte category; #endregion #region Constructors /// Initializes a new instance of the VoiceEvent class. /// The amount of time before this event. /// The category identifier (0x0 through 0xF) for this voice event. /// The channel (0x0 through 0xF) for this voice event. protected VoiceEvent(long deltaTime, byte givenCategory, MidiChannel channel) : base(deltaTime) { // Validate the parameters if (givenCategory > 0xF) { throw new ArgumentOutOfRangeException(nameof(givenCategory), givenCategory, "Category values must be in the range from 0x0 to 0xF."); } // Store the data this.category = givenCategory; this.Channel = channel; } /// Initializes a new instance of the VoiceEvent class. /// The amount of time before this event. protected VoiceEvent(long deltaTime) : base(deltaTime) { } #endregion #region Properties /// Gets The first parameter as sent in the MIDI message. /// General musical property. public abstract byte Parameter1 { get; } /// Gets The second parameter as sent in the MIDI message. /// General musical property. public abstract byte Parameter2 { get; } /// Gets the status identifier (0x0 through 0xF) for this voice event. /// General musical property. [UsedImplicitly] public byte Category => this.category; /// Gets or sets the channel (0x0 through 0xF) for this voice event. /// General musical property. public MidiChannel Channel { get; set; } //// virtual (11/2010) /// Gets the status byte for the event message (combination of category and channel). /// General musical property. public byte Status => this.GetStatusByte(); /// Gets the word that represents this event as a MIDI event message. [UsedImplicitly] internal int Message => this.Status | (this.Parameter1 << 8) | (this.Parameter2 << 16); #endregion #region To String /// Generate a string representation of the event. /// A string representation of the event. public override string ToString() { var sb = new StringBuilder(); sb.Append(base.ToString()); sb.Append(" \t"); sb.Append("C=" + this.Channel); //// sb.Append("\t"); //// sb.Append("0x"); //// sb.Append(this.Channel.ToString("X1", System.Globalization.CultureInfo.CurrentCulture.NumberFormat)); return sb.ToString(); } #endregion #region Methods /// Write the event to the output stream. /// The stream to which the event should be written. public override void Write(Stream outputStream) { if (outputStream == null) { return; } //// Write out the base event information base.Write(outputStream); // Write out the status byte outputStream.WriteByte(this.GetStatusByte()); } /// Gets the status byte for the message event. /// The status byte (combination of category and channel) for the message event. private byte GetStatusByte() { // The command is the upper 4 bits and the channel is the lower 4. return (byte)((this.category << 4) | (byte)this.Channel); //// was cast to int before this.category } #endregion } }